#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <math.h>

typedef float (*fun_two) (float a, float b);
typedef float (*fun_one) (float);

typedef struct
{
  int arg_num;
  union
  {
    fun_one one_arg;
    fun_two two_arg;
  } fun;
} operation;

float read_num (char *prompt);
float plus (float a, float b);
float minus (float a, float b);
float multiply (float a, float b);
float devide (float a, float b);
void read_operation (operation * op);
void print_select_list (void);

int
main ()
{
  operation op = { 0, {NULL} };
  float n1 = 0;
  float n2 = 0;
  float result = 0;
  do
    {
      print_select_list ();
      read_operation (&op);
    }
  while (op.arg_num == 0);
  n1 = read_num ("Input a number: ");
  if (op.arg_num == 1)
    {
      result = (*op.fun.one_arg) (n1);
    }
  else
    {
      n2 = read_num ("Input a number: ");
      result = (op.fun.two_arg) (n1, n2);
    }
  printf ("Result: %.3G\n", result);
  return EXIT_SUCCESS;
}

float
read_num (char *prompt)
{
  char buf[10];
  char *endptr = NULL;
  float val;
  int last;
  while (1)
    {
      printf ("%s", prompt);
      fgets (buf, sizeof (buf), stdin);
      last = strlen (buf) - 1;
      if (buf[last] == '\n')
	{
	  buf[last] = '\0';
	}
      val = strtod (buf, &endptr);
      if (endptr != NULL && *endptr != '\0')
	{
	  printf ("%s is not a valid number.\n", buf);
	}
      else
	{
	  return val;
	}
    }
}

void
print_select_list ()
{
  printf ("Select a operation\n");
  printf ("1 +\n");
  printf ("2 -\n");
  printf ("3 *\n");
  printf ("4 /\n");
  printf ("5 sqrt\n");
}

void
read_operation (operation * op)
{
  int index = 0;
  index = (int) read_num ("Your selection is: ");
  switch (index)
    {
    case 1:
      op->arg_num = 2;
      op->fun.two_arg = plus;
      break;
    case 2:
      op->arg_num = 2;
      op->fun.two_arg = minus;
      break;
    case 3:
      op->arg_num = 2;
      op->fun.two_arg = multiply;
      break;
    case 4:
      op->arg_num = 2;
      op->fun.two_arg = devide;
      break;
    case 5:
      op->arg_num = 1;
      op->fun.one_arg = sqrtf;
      break;
    }
}


float
plus (float a, float b)
{
  return a + b;
}

float
minus (float a, float b)
{
  return a - b;
}

float
multiply (float a, float b)
{
  return a * b;
}

float
devide (float a, float b)
{
  return a / b;
}
